package longshu.data.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import lombok.extern.slf4j.Slf4j;
import longshu.data.common.context.SpringContext;
import longshu.data.common.ds.DataSourceKey;
import longshu.data.common.ds.DynamicDataSource;
import longshu.data.common.ds.TargetDSInterceptor;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.support.RegexpMethodPointcutAdvisor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.init.DatabasePopulator;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.util.Map;

/**
 * DataSourceConfig
 *
 * @author LongShu 2018/01/18
 */
@Slf4j
@Configuration
@EnableTransactionManagement
public class DataSourceConfig implements TransactionManagementConfigurer, ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext context) {
        SpringContext.setContext(context);
    }

    /**
     * 数据库初始化
     */
    @PostConstruct
    public void runScripts() {
        Map<String, DruidDataSource> dataSourceMap = SpringContext.getContext().getBeansOfType(DruidDataSource.class);
        for (Map.Entry<String, DruidDataSource> entry : dataSourceMap.entrySet()) {
            String platform = entry.getKey().replace("DataSource", "");
            String script = "classpath:META-INF/sql/schema-" + platform + ".sql";
            Resource resource = SpringContext.getContext().getResource(script);
            if (resource.exists()) {
                log.info("resource:{}", resource);
                DatabasePopulator populator = new ResourceDatabasePopulator(resource);
                DatabasePopulatorUtils.execute(populator, entry.getValue());
            }
        }
    }

    //@Bean
    public PointcutAdvisor targetDSAdvisor() {
        TargetDSInterceptor interceptor = new TargetDSInterceptor();
        String[] patterns = {"longshu.data.service.*"};
        return new RegexpMethodPointcutAdvisor(patterns, interceptor);
    }

    @Bean
    public DynamicDataSource dataSource() {
        Map<String, DataSource> dataSourceMap = SpringContext.getContext().getBeansOfType(DataSource.class);
        /*
         * 将其他数据源添加到DynamicDataSource
         */
        for (Map.Entry<String, DataSource> entry : dataSourceMap.entrySet()) {
            DynamicDataSource.addDataSource(entry.getKey(), entry.getValue());
        }
        DynamicDataSource dataSource = DynamicDataSource.getInstance();
        // 默认数据源
        dataSource.setDefaultTargetDataSource(dataSourceMap.get(DataSourceKey.SQLITE));
        return dataSource;
    }

    @Bean(name = DataSourceKey.MYSQL)
    @ConfigurationProperties(prefix = "spring.datasource.mysql")
    public DruidDataSource mysqlDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = DataSourceKey.H2)
    @ConfigurationProperties(prefix = "spring.datasource.h2")
    public DruidDataSource h2DataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = DataSourceKey.SQLITE)
    @ConfigurationProperties(prefix = "spring.datasource.sqlite")
    public DruidDataSource sqliteDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = DataSourceKey.HSQLDB)
    @ConfigurationProperties(prefix = "spring.datasource.hsqldb")
    public DruidDataSource hsqldbDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

    /**
     * @see org.springframework.transaction.annotation.TransactionManagementConfigurer
     */
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return transactionManager();
    }

}
